package com.niiwoo.civet.mobile.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.activity.stage.service.prize.ActivityPrizeDubboService;
import com.niiwoo.civet.account.dto.common.BankCardDTO;
import com.niiwoo.civet.account.dto.common.BankTypeDTO;
import com.niiwoo.civet.account.dto.common.WithdrawOrderDTO;
import com.niiwoo.civet.account.dto.request.SubmitWithdrawRequestDTO;
import com.niiwoo.civet.account.dto.request.WithdrawOrderQueryRequest;
import com.niiwoo.civet.account.dto.response.AccountBaseResponse;
import com.niiwoo.civet.account.dto.response.WithdrawOrderResponseDTO;
import com.niiwoo.civet.account.dto.response.WithdrawT0CheckResponse;
import com.niiwoo.civet.account.enums.WithdrawAutoType;
import com.niiwoo.civet.account.enums.WithdrawBusinessTypeEnum;
import com.niiwoo.civet.account.enums.WithdrawOrderStatusEnum;
import com.niiwoo.civet.account.service.AccountDubboService;
import com.niiwoo.civet.account.service.WithdrawDubboService;
import com.niiwoo.civet.account.service.bankcard.BankCardDubboService;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.civet.base.enums.ChannelCodeEnum;
import com.niiwoo.civet.mobile.vo.common.BankCardVO;
import com.niiwoo.civet.mobile.vo.common.BankTypeVO;
import com.niiwoo.civet.mobile.vo.common.FormVO;
import com.niiwoo.civet.mobile.vo.common.UserAccountVO;
import com.niiwoo.civet.mobile.vo.request.withdraw.CommonWithdrawCheckRequestVO;
import com.niiwoo.civet.mobile.vo.request.withdraw.SubmitWithdrawRequestVO;
import com.niiwoo.civet.mobile.vo.request.withdraw.WithdrawOrderListRequestVO;
import com.niiwoo.civet.mobile.vo.request.withdraw.WithdrawT0EnableCheckRequestVO;
import com.niiwoo.civet.mobile.vo.response.withdraw.*;
import com.niiwoo.civet.trade.dto.common.ProjectBorrowerPlanDTO;
import com.niiwoo.civet.trade.dto.common.ProjectBorrowerSummaryDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDTO;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.civet.trade.service.myloan.MyLoanDubboService;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.civet.user.dto.response.UserAccountPropertyResponse;
import com.niiwoo.civet.user.dto.response.ValidUserForbidResponseDTO;
import com.niiwoo.civet.user.enums.UserForbidTypeEnum;
import com.niiwoo.civet.user.service.UserAccountDubboService;
import com.niiwoo.civet.user.service.UserForbidDubboService;
import com.niiwoo.tripod.base.enums.UserTypeEnum;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoGatewayService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.UserDeviceEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.enums.WithdrawFormEnum;
import com.niiwoo.tripod.lanmao.enums.WithdrawTypeEnum;
import com.niiwoo.tripod.lanmao.request.ConfirmWithdrawRequest;
import com.niiwoo.tripod.lanmao.request.InterceptWithdrawRequest;
import com.niiwoo.tripod.lanmao.request.QueryUserInformationRequest;
import com.niiwoo.tripod.lanmao.request.WithdrawRequest;
import com.niiwoo.tripod.lanmao.response.ConfirmWithdrawResponse;
import com.niiwoo.tripod.lanmao.response.InterceptWithdrawResponse;
import com.niiwoo.tripod.lanmao.response.LanMaoGatewayDTO;
import com.niiwoo.tripod.lanmao.response.QueryUserInformationResponse;
import com.niiwoo.tripod.provider.dto.response.PageResponseDTO;
import com.niiwoo.tripod.web.annotation.AuthIgnore;
import com.niiwoo.tripod.web.util.PrincipalContext;
import com.niiwoo.tripod.web.vo.PageResponseVO;
import com.niiwoo.tripod.web.vo.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Strings;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * Created by wangjichao on 2017/10/16.
 */
@RestController
@RequestMapping("/withdraw")
@Api(tags = "提现", description = "/withdraw")
@Slf4j
public class WithdrawController {

    @Reference(version = "1.0.0")
    private WithdrawDubboService withdrawDubboService;
    @Reference(version = "1.0.0")
    private UserForbidDubboService userForbidDubboService;
    @Reference(version = "1.0.0")
    private MyLoanDubboService myLoanDubboService;
    @Reference(version = "1.0.0")
    private ActivityPrizeDubboService activityPrizeDubboService;
    @Reference(version = "1.0.0")
    private AccountDubboService accountDubboService;
    @Reference(version = "1.0.0")
    private BankCardDubboService bankCardDubboService;
    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;
    @Reference(version = "1.0.0")
    private ProjectDubboService projectDubboService;
    @Reference(version = "1.0.0")
    private UserAccountDubboService userAccountDubboService;
    @Autowired
    private LanMaoGatewayService lanMaoGatewayService;
    @Autowired
    private LanMaoDirectService lanMaoDirectService;
    @Autowired
    private LanMaoSequence lanMaoSequence;

    private static final BigDecimal minWithdrawAmount = new BigDecimal("100.00");

    /**
     * 提现检查
     *
     * @return
     */
    @PostMapping("/check")
    @ApiOperation("提现检查")
    public Result<WithdrawCheckResponseVO> withdrawCheck() {
        String userId = PrincipalContext.getUserId();

        //用户是否被禁止提现
        Boolean forbidWithdraw = Boolean.FALSE;
        ValidUserForbidResponseDTO validUserForbid = userForbidDubboService.queryValidUserForbidInfo(userId, UserForbidTypeEnum.WITHDRAW);
        if (Objects.nonNull(validUserForbid)) {
            forbidWithdraw = Boolean.TRUE;
        }
        //用户是否有逾期未还的贷款
        Boolean hasOverdueRepayment = this.hasOverdueRepayment(userId);
        //用户当天是否需要还款
        Boolean hasTodayRepayment = this.hasTodayRepayment(userId);

        //返回
        WithdrawCheckResponseVO responseVO = new WithdrawCheckResponseVO();
        responseVO.setForbidWithdraw(forbidWithdraw);
        responseVO.setForbidWithdrawMsg(validUserForbid == null ? null :validUserForbid.getForbidDesc());
        responseVO.setHasOverdueRepayment(hasOverdueRepayment);
        responseVO.setHasTodayRepayment(hasTodayRepayment);
        return Result.with(responseVO);
    }

    @PostMapping("/t0EnableCheck")
    @ApiOperation("是否支持T0提现检查")
    public Result<WithdrawT0EnableCheckResponseVO> withdrawT0EnableCheck(@RequestBody @Valid WithdrawT0EnableCheckRequestVO requestVO) {
        //获取用户账户信息
        String userId = PrincipalContext.getUserId();
        UserRoleEnum userRoleEnum = UserRoleEnum.enumOf(requestVO.getAccountUserRole());
        Assert.notNull(userRoleEnum, "账户角色不正确");

        //检查是否支持能T0提现
        String t0EnableConfig = tradeConfigDubboService.selectTradeConfigByEmun(TradeConfigEnum.FAST_WITHDRAW_ON_OFF);//T0提现开关:0关，1开
        Boolean t0Enable = Boolean.FALSE;
        if(StringUtils.equals("1",t0EnableConfig)){
            WithdrawT0CheckResponse withdrawT0CheckResponse = withdrawDubboService.checkT0Enable(userId, userRoleEnum, requestVO.getAmount());
            t0Enable = withdrawT0CheckResponse.getT0Enable();
        }

        //返回结果
        WithdrawT0EnableCheckResponseVO responseVO = new WithdrawT0EnableCheckResponseVO();
        responseVO.setT0Enable(t0Enable);
        return Result.with(responseVO);
    }

    /**
     * 提现首页查询(你我金融用户+企业投资人)
     *
     * @return
     */
    @PostMapping("/index")
    @ApiOperation("提现首页查询")
    public Result<WithdrawIndexResponseVO> withdrawIndex() {
        log.info("withdrawIndex start:{}",JSON.toJSONString(PrincipalContext.getUserPrincipal()));
        String userId = PrincipalContext.getUserId();

        List<AccountBaseResponse> accountList = new ArrayList<>();//用户账户列表
        BankCardDTO bankCardDTO;//绑定的银行卡信息
        log.info("是否个人用户：{}",UserTypeEnum.PERSONAL == PrincipalContext.getUserPrincipal().getUserType());
        UserTypeEnum userType = PrincipalContext.getUserPrincipal().getUserType();
        if(null == PrincipalContext.getUserPrincipal().getUserType()){
            userType = UserTypeEnum.PERSONAL;
        }

        if(UserTypeEnum.PERSONAL == userType){
            //个人用户
            accountList = accountDubboService.listNiiwooAccountByUserId(userId);
            bankCardDTO = bankCardDubboService.getUserBankCardInfo(userId);
        }else {
            //机构用户：只限定是企业投资人
            String orgId = userId;//企业投资人账户中的机构id等于用户id
            AccountBaseResponse accountBaseResponse = accountDubboService.loadOrgAccount(userId, orgId);
            accountList.add(accountBaseResponse);
            bankCardDTO = bankCardDubboService.getUserBankCardByAccountId(accountBaseResponse.getAccountId());
        }
        log.info("accountList:{}， bankCardDTO:{}", JSON.toJSONString(accountList), JSON.toJSONString(bankCardDTO));

        //查询用户信息
        UserAccountPropertyResponse userAccountPropertyResponse = userAccountDubboService.getAccountProperty(userId);

        //计算推荐的提现账户类型
        UserRoleEnum defaultWithdrawAccountRole = calcDefaultWithdrawAccountRole(userId, accountList);

        //查询基础配置信息
        List<TradeConfigEnum> tradeConfigEnumList = new ArrayList<>();
        tradeConfigEnumList.add(TradeConfigEnum.WITHDRAWFEE);//正常提现手续费率
        tradeConfigEnumList.add(TradeConfigEnum.WITHDRAW_FEE_IN_ACTIVITY);//正常提现活动期手续费率
        tradeConfigEnumList.add(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_BEGIN);//正常提现活动开始时间
        tradeConfigEnumList.add(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_END);//正常提现活动截止时间
        tradeConfigEnumList.add(TradeConfigEnum.FASTWITHDRAWFEE);//快速提现手续费率
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_FEE_IN_ACTIVITY);//快速提现活动期手续费率
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_BEGIN);//快速提现活动开始时间
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_END);//快速提现活动截止时间
        tradeConfigEnumList.add(TradeConfigEnum.SINGLEWITHDRAWMAXAMOUNT);//单次提现封顶手续费
        tradeConfigEnumList.add(TradeConfigEnum.WITHDRAWMAXAMOUNT);//单次提现最高限额
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_ON_OFF);//T0提现开关:0关，1开
        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_MARK);//T0提现的文案描述
        tradeConfigEnumList.add(TradeConfigEnum.NORMAL_WITHDRAW_ON_OFF);//T1提现开关:0关，1开
        tradeConfigEnumList.add(TradeConfigEnum.NORMAL_WITHDRAW_MARK);//T1提现的文案描述
        log.info("tradeConfigDubboService={}",tradeConfigDubboService);
        Map<String, String> tradeConfigMap = tradeConfigDubboService.selectTradeConfigByEmuns(tradeConfigEnumList);
        log.info("tradeConfigMap={}",JSON.toJSONString(tradeConfigMap));

        BigDecimal normalwithdrawFeeRate = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.WITHDRAWFEE.getConfigKey()));
        BigDecimal fastWithdrawFeeRate = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.FASTWITHDRAWFEE.getConfigKey()));
        BigDecimal maxWithdrawFeeAmount = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.SINGLEWITHDRAWMAXAMOUNT.getConfigKey()));
        BigDecimal maxWithdrawAmount = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.WITHDRAWMAXAMOUNT.getConfigKey()));

        //获取正常提现和快速提现的优惠活动手续费率
        BigDecimal normalWithdrawFeeRateInActivity = normalwithdrawFeeRate;//没有活动时是原价
        BigDecimal fastWithdrawFeeRateInActivity = fastWithdrawFeeRate;//没有活动时是原价
        if(UserTypeEnum.PERSONAL == userType){
            //获取正常提现手续费活动价
            String normalWithdrawFeeActivityTimeBegin = tradeConfigMap.get(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_BEGIN.getConfigKey());
            String normalWithdrawFeeActivityTimeEnd = tradeConfigMap.get(TradeConfigEnum.NORMAL_WITHDRAW_ACTIVITY_TIME_END.getConfigKey());

            DateTimeFormatter dft = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
            if(StringUtils.isNotEmpty(normalWithdrawFeeActivityTimeBegin) && StringUtils.isNotEmpty(normalWithdrawFeeActivityTimeEnd)){
                //判断当前时间正常提现是否有优惠活动
                if(DateTime.parse(normalWithdrawFeeActivityTimeBegin, dft).isBeforeNow()  &&  DateTime.parse(normalWithdrawFeeActivityTimeEnd, dft).isAfterNow()){
                    normalWithdrawFeeRateInActivity = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.WITHDRAW_FEE_IN_ACTIVITY.getConfigKey()));
                }
            }

            //获取快速提现手续费活动价
            String fastWithdrawFeeActivityTimeBegin = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_BEGIN.getConfigKey());
            String fastWithdrawFeeActivityTimeEnd = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_ACTIVITY_TIME_END.getConfigKey());
            if(StringUtils.isNotEmpty(normalWithdrawFeeActivityTimeBegin) && StringUtils.isNotEmpty(fastWithdrawFeeActivityTimeEnd)){
                //判断当前时间快速提现是否有优惠活动
                if(DateTime.parse(fastWithdrawFeeActivityTimeBegin, dft).isBeforeNow()  &&  DateTime.parse(fastWithdrawFeeActivityTimeEnd, dft).isAfterNow()){
                    fastWithdrawFeeRateInActivity = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_FEE_IN_ACTIVITY.getConfigKey()));
                }
            }
        }

        //判断T0和T1提现是否可用及显示的文案内容
        String fastWithdrawOnOff = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_ON_OFF.getConfigKey());
        String fastWithdrawMark = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_MARK.getConfigKey());
        String normalWithdrawOnOff = tradeConfigMap.get(TradeConfigEnum.NORMAL_WITHDRAW_ON_OFF.getConfigKey());
        String normalWithdrawMark = tradeConfigMap.get(TradeConfigEnum.NORMAL_WITHDRAW_MARK.getConfigKey());
        Boolean t0Enable = StringUtils.equals("1",fastWithdrawOnOff) ? Boolean.TRUE : Boolean.FALSE;
        Boolean t1Enable = StringUtils.equals("1",normalWithdrawOnOff) ? Boolean.TRUE : Boolean.FALSE;

        if(t1Enable){
            DateTime preLimit = new DateTime();
            preLimit = preLimit.withHourOfDay(22).withMinuteOfHour(50).withSecondOfMinute(0);
            DateTime postLimit = new DateTime();
            postLimit = postLimit.withHourOfDay(0).withMinuteOfHour(10).withSecondOfMinute(0);
            if (preLimit.isBeforeNow() || postLimit.isAfterNow()) {
                t1Enable = Boolean.FALSE;//当日22:50-次日00:10之间默认不允许T1提现
                if(!t0Enable){
                    //此时也不允许T0提现，所以还得放开T1提现
                    t1Enable = Boolean.TRUE;
                }
            }
        }

        //返回
        WithdrawIndexResponseVO withdrawIndexResponseVO = new WithdrawIndexResponseVO();
        withdrawIndexResponseVO.setUserName(userAccountPropertyResponse.getRealName());
        withdrawIndexResponseVO.setAccountList(transToUserAccountVO(accountList));
        withdrawIndexResponseVO.setBankCard(transToBankCardVO(bankCardDTO));
        withdrawIndexResponseVO.setWithdrawFeeRate(normalwithdrawFeeRate);
        withdrawIndexResponseVO.setFastWithdrawIncreaseFeeRate(fastWithdrawFeeRate.subtract(normalwithdrawFeeRate));
        withdrawIndexResponseVO.setFastWithdrawFeeRate(fastWithdrawFeeRate);
        withdrawIndexResponseVO.setActivityWithdrawFeeRate(normalWithdrawFeeRateInActivity);
        withdrawIndexResponseVO.setActivityFastWithdrawFeeRate(fastWithdrawFeeRateInActivity);
        withdrawIndexResponseVO.setMaxWithdrawFeeAmount(maxWithdrawFeeAmount);
        withdrawIndexResponseVO.setMinWithdrawAmount(minWithdrawAmount);
        withdrawIndexResponseVO.setMaxWithdrawAmount(maxWithdrawAmount);
        if(Objects.nonNull(defaultWithdrawAccountRole)){
            withdrawIndexResponseVO.setDefaultWithdrawAccountRole(defaultWithdrawAccountRole.getValue());
        }
        withdrawIndexResponseVO.setT0Enable(t0Enable);
        withdrawIndexResponseVO.setT1Enable(t1Enable);
        withdrawIndexResponseVO.setT0WithdrawMark(fastWithdrawMark);
        withdrawIndexResponseVO.setT1WithdrawMark(normalWithdrawMark);

        return Result.with(withdrawIndexResponseVO);
    }
    
    /**
     * 普通提现时间校验
     *
     * @return
     */
    @PostMapping("/commonWithdrawCheck")
    @ApiOperation("普通提现时间校验")
    public Result<CommonWithdrawCheckResponseVO> commonWithdrawCheck(@RequestBody @Valid CommonWithdrawCheckRequestVO requestVO) {
        String userId = PrincipalContext.getUserId();

            //查询是否可以T1提现的后台开关
            Boolean t1Enable = Boolean.TRUE;
            if(t1Enable){
            //当日22:50-次日00:10之间默认不允许T1提现
            DateTime preLimit = new DateTime();
            preLimit = preLimit.withHourOfDay(22).withMinuteOfHour(50).withSecondOfMinute(0);
            DateTime postLimit = new DateTime();
            postLimit = postLimit.withHourOfDay(0).withMinuteOfHour(10).withSecondOfMinute(0);
            if (preLimit.isBeforeNow() || postLimit.isAfterNow()) {
                t1Enable = Boolean.FALSE;
                //此时不允许T1提现，那么查询是否允许T0提现
                String t0EnableConfig = tradeConfigDubboService.selectTradeConfigByEmun(TradeConfigEnum.FAST_WITHDRAW_ON_OFF);//T0提现开关:0关，1开
                if(StringUtils.equals("1",t0EnableConfig)){
                    //开关允许T0提现，此时再查询业务上是否允许T0
                    UserRoleEnum userRoleEnum = UserRoleEnum.enumOf(requestVO.getAccountUserRole());
                    Assert.notNull(userRoleEnum, "账户角色不正确");
                    WithdrawT0CheckResponse t0Check = withdrawDubboService.checkT0Enable(userId, userRoleEnum, requestVO.getAmount());
                    if (!t0Check.getT0Enable()) {
                        //此时也不允许T0提现，所以还得放开T1提现
                        t1Enable = Boolean.TRUE;
                    }
                }
            }
        }

        //返回
        CommonWithdrawCheckResponseVO response = new CommonWithdrawCheckResponseVO();
        response.setEnable((byte) 0);
        if(t1Enable){
            response.setEnable((byte) 1);
        }
    	return Result.with(response);
    }


    /**
     * 提交提现申请
     *
     * @return
     */
    @PostMapping("/submit")
    @ApiOperation("提交提现申请，返回懒猫表单")
    public Result<SubmitWithdrawResponseVO> submitWithdraw(@RequestBody @Valid SubmitWithdrawRequestVO requestVO) {
//        /**
//         * 检查
//         */
//        //查询T0和T1提现的开关配置
//        List<TradeConfigEnum> tradeConfigEnumList = new ArrayList<>();
//        tradeConfigEnumList.add(TradeConfigEnum.FAST_WITHDRAW_ON_OFF);//T0提现开关:0关，1开
//        tradeConfigEnumList.add(TradeConfigEnum.NORMAL_WITHDRAW_ON_OFF);//T1提现开关:0关，1开
//        Map<String, String> tradeConfigMap = tradeConfigDubboService.selectTradeConfigByEmuns(tradeConfigEnumList);
//
//        String fastWithdrawOnOff = tradeConfigMap.get(TradeConfigEnum.FAST_WITHDRAW_ON_OFF.getConfigKey());
//        String normalWithdrawOnOff = tradeConfigMap.get(TradeConfigEnum.NORMAL_WITHDRAW_ON_OFF.getConfigKey());
//        if(requestVO.getWithdrawType().byteValue() == 1){
//            Assert.isTrue(StringUtils.equals("1",normalWithdrawOnOff),"请打开T1提现的配置开关");
//        }else if(requestVO.getWithdrawType().byteValue() == 2){
//            Assert.isTrue(StringUtils.equals("1",fastWithdrawOnOff),"请打开T0提现的配置开关");
//        }

        //生成提现订单
        SubmitWithdrawRequestDTO serviceRequest = new SubmitWithdrawRequestDTO();
        serviceRequest.setAccountId(requestVO.getAccountId());
        serviceRequest.setAmount(requestVO.getAmount());
        serviceRequest.setPrizeId(requestVO.getPrizeId());
        serviceRequest.setUserId(PrincipalContext.getUserId());
        serviceRequest.setWithdrawAutoType(WithdrawAutoType.NORMAL);
        serviceRequest.setWithdrawBusinessType(WithdrawBusinessTypeEnum.NORMAL_WITHDRAW);
        serviceRequest.setWithdrawType(WithdrawTypeEnum.enumOf(requestVO.getWithdrawType()));
        WithdrawOrderDTO withdrawOrderDTO = withdrawDubboService.submitWithdraw(serviceRequest);

        //调用懒猫组件生成表单（待确认提现无需传递WithdrawType参数）
        WithdrawRequest withdrawRequest = new WithdrawRequest();
        withdrawRequest.setNiiwooRedirectUrl(requestVO.getRedirectUrl());
        withdrawRequest.setUserDevice(UserDeviceEnum.MOBILE);
        withdrawRequest.setWithdrawForm(WithdrawFormEnum.CONFIRMED);
        withdrawRequest.setPlatformUserNo(withdrawOrderDTO.getAccountNo());
        withdrawRequest.setRequestNo(withdrawOrderDTO.getRequestNo());
        withdrawRequest.setExpired(withdrawOrderDTO.getExpired());
        withdrawRequest.setAmount(withdrawOrderDTO.getAmount());
        //佣金传递0上海银行会报错
        if(withdrawOrderDTO.getFee().compareTo(BigDecimal.ZERO) > 0){
            withdrawRequest.setCommission(withdrawOrderDTO.getFee());
        }

        withdrawRequest.setTimestamp(new Date());

        LanMaoGatewayDTO lanMaoGatewayDTO = lanMaoGatewayService.withdraw(withdrawRequest);
        SubmitWithdrawResponseVO response = new SubmitWithdrawResponseVO();
        FormVO formVO = new FormVO();
        formVO.setAction(lanMaoGatewayDTO.getAction());
        formVO.setParams(lanMaoGatewayDTO.getParams());
        response.setForm(formVO);
        return Result.with(response);
    }

    /**
     * 提现记录列表(个人用户+企业投资者)
     *
     * @return
     */
    @PostMapping("/listRecord")
    @ApiOperation("提现记录查询")
    public Result<ListWithdrawRecordResponseVO> listWithdrawRecord(@RequestBody WithdrawOrderListRequestVO requestVO) {
        //查询用户在你我金融的账户，考虑未上存管前的提现记录中accountId=-1
        String userId = PrincipalContext.getUserId();
        String orgId = requestVO.getOrgId();
        List<Long> accountIds;
        BigDecimal totalAmount = BigDecimal.ZERO;
        if(Strings.isNullOrEmpty(orgId) || OrgConstant.NIIWOO_ORG_ID.equals(orgId)){
            //个人用户
            accountIds = accountDubboService.listNiiwooAccountByUserId(userId).stream().map(AccountBaseResponse::getAccountId).
                    collect(Collectors.toList());
            if( null != accountIds ){
                accountIds.add(-1L);
            }else{
                accountIds = Collections.singletonList(-1L);
            }

            //统计用户成功提现的总额
            totalAmount = withdrawDubboService.queryUserTotalSuccessAmount(userId);
        }else {
            //企业投资者
            AccountBaseResponse accountBaseResponse = accountDubboService.loadOrgAccount(userId,orgId);
            accountIds = Arrays.asList(accountBaseResponse.getAccountId());
        }

        List<WithdrawOrderStatusEnum> statusEnumList = new ArrayList<>();
        if(Objects.isNull(requestVO.getStatus()) || requestVO.getStatus() == 0){
            //查询全部的提现记录
            statusEnumList.add(WithdrawOrderStatusEnum.PRE_SUBMISSION);
            statusEnumList.add(WithdrawOrderStatusEnum.WAIT_CONFIRM);
            statusEnumList.add(WithdrawOrderStatusEnum.OUTING);
            statusEnumList.add(WithdrawOrderStatusEnum.SUCCESS);
            statusEnumList.add(WithdrawOrderStatusEnum.FAIL);
        }else if(requestVO.getStatus() == 1){
            //只查成功的提现记录
            statusEnumList.add(WithdrawOrderStatusEnum.SUCCESS);
        }else if(requestVO.getStatus() == 2){
            //只查失败的提现记录
            statusEnumList.add(WithdrawOrderStatusEnum.FAIL);
        }else if(requestVO.getStatus() == 3){
            //只查处理中的提现记录
            statusEnumList.add(WithdrawOrderStatusEnum.PRE_SUBMISSION);
            statusEnumList.add(WithdrawOrderStatusEnum.WAIT_CONFIRM);
            statusEnumList.add(WithdrawOrderStatusEnum.OUTING);
        }else {
            Assert.isTrue(false,"status参数值不合法");
        }

        //分页查询
        WithdrawOrderQueryRequest withdrawOrderQueryRequest = new WithdrawOrderQueryRequest();
        withdrawOrderQueryRequest.setUserId(userId);
        withdrawOrderQueryRequest.setAccountIds(accountIds);
        withdrawOrderQueryRequest.setStatusEnumList(statusEnumList);
        withdrawOrderQueryRequest.setMinWithdrawTime(requestVO.getMinWithdrawTime());
        withdrawOrderQueryRequest.setMaxWithdrawTime(requestVO.getMaxWithdrawTime());
        withdrawOrderQueryRequest.setPageNumber(requestVO.getPageNumber());
        withdrawOrderQueryRequest.setPageSize(requestVO.getPageSize());
        PageResponseDTO<WithdrawOrderResponseDTO> responseDTO = withdrawDubboService.pageWithdrawOrders(withdrawOrderQueryRequest);

        //组装返回的数据格式
        List<WithdrawRecordVO> withdrawRecordVOList = responseDTO.getItems().stream().map(e -> {
            WithdrawRecordVO vo = new WithdrawRecordVO();
            vo.setAmount(e.getRealAmount());
            vo.setAccountRole(e.getAccountRole());
            vo.setTime(e.getCreateTime());

            //预提交未收到存管回调的单据作为密码未验证
            if(WithdrawOrderStatusEnum.PRE_SUBMISSION.getCode().equals(e.getStatus())){
                vo.setStatus(Byte.valueOf("3"));//密码未验证
            }
            //待确认和出款中作为提现处理中
            else if(WithdrawOrderStatusEnum.WAIT_CONFIRM.getCode().equals(e.getStatus())
                    || WithdrawOrderStatusEnum.OUTING.getCode().equals(e.getStatus())){
                vo.setStatus(Byte.valueOf("0"));
            }
            //提现成功
            else if(WithdrawOrderStatusEnum.SUCCESS.getCode().equals(e.getStatus())){
                vo.setStatus(Byte.valueOf("1"));
            }
            //提现失败
            else if(WithdrawOrderStatusEnum.FAIL.getCode().equals(e.getStatus())){
                vo.setStatus(Byte.valueOf("2"));
            }
            return vo;
        }).collect(Collectors.toList());

        PageResponseVO<WithdrawRecordVO> pageVO = new PageResponseVO<>();
        pageVO.setTotalCount(responseDTO.getTotalCount());
        pageVO.setTotalPage(responseDTO.getTotalPage());
        pageVO.setItems(withdrawRecordVOList);

        //组装返回结果
        ListWithdrawRecordResponseVO responseVO = new ListWithdrawRecordResponseVO();
        responseVO.setPage(pageVO);
        responseVO.setTotalAmount(totalAmount);
        responseVO.setServerDate(new Date());
        return Result.with(responseVO);
    }


    private List<UserAccountVO> transToUserAccountVO(List<AccountBaseResponse> accountBaseResponseList) {
        List<UserAccountVO> userAccountVOList = new ArrayList<>(accountBaseResponseList.size());
        for (AccountBaseResponse accountBaseResponse : accountBaseResponseList) {
            UserAccountVO userAccountVO = new UserAccountVO();
            userAccountVO.setAccountId(accountBaseResponse.getAccountId());
            userAccountVO.setAccountNo(accountBaseResponse.getAccountNo());
            userAccountVO.setAccountRole(accountBaseResponse.getAccountRole());
            userAccountVO.setAvailableAmount(accountBaseResponse.getAvailableAmount());
            userAccountVO.setActiveAccount(accountBaseResponse.getImportUserActiva());

            userAccountVOList.add(userAccountVO);
        }


        return userAccountVOList;
    }

    private BankCardVO transToBankCardVO(BankCardDTO dto) {
        BankTypeDTO bankTypeDTO = dto.getBankType();
        BankTypeVO bankTypeVO = new BankTypeVO();
        bankTypeVO.setBankTypeId(bankTypeDTO.getBankTypeId());
        bankTypeVO.setBankCode(bankTypeDTO.getBankCode());
        bankTypeVO.setBankName(bankTypeDTO.getBankName());

        BankCardVO vo = new BankCardVO();
        vo.setRealName(dto.getRealName());
        vo.setBankCardId(dto.getBankCardId());
        vo.setBankAccountNo(dto.getBankAccountNo());
        vo.setBankType(bankTypeVO);

        return vo;
    }

    //判断用户当天是否需要还款
    private Boolean hasTodayRepayment(String userId) {
        Boolean hasTodayRepayment = Boolean.FALSE;
        List<ProjectBorrowerPlanDTO> planDTOList = myLoanDubboService.queryMyLoanPlanByToday(userId);
        if (!CollectionUtils.isEmpty(planDTOList)) {
            //排除考拉理财等渠道的项目，排除机构项目
            List<ProjectDTO> projectDTOList = planDTOList.stream().map(e -> projectDubboService.selectProjectById(e.getProjectId()))
                    .filter(projectDTO -> !ChannelCodeEnum.KAOLA.getChanelCode().equals(projectDTO.getChannelCode()))
                    .filter(projectDTO -> StringUtils.isBlank(projectDTO.getOrgId()) || OrgConstant.NIIWOO_ORG_ID.equals(projectDTO.getOrgId()))
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(projectDTOList)) {
                hasTodayRepayment = Boolean.TRUE;
            }
        }

        return hasTodayRepayment;
    }

    //判断用户是否有逾期未还的贷款
    private Boolean hasOverdueRepayment(String userId) {
        Boolean hasOverdueRepayment = Boolean.FALSE;
        List<ProjectBorrowerSummaryDTO> overdueList = myLoanDubboService.queryMyLoanOverdue(userId);
        if (!CollectionUtils.isEmpty(overdueList)) {
            //排除考拉理财等渠道的项目，排除机构项目
            List<ProjectDTO> projectDTOList = overdueList.stream().map(e -> projectDubboService.selectProjectById(e.getProjectId()))
                    .filter(projectDTO -> !ChannelCodeEnum.KAOLA.getChanelCode().equals(projectDTO.getChannelCode()))
                    .filter(projectDTO -> StringUtils.isBlank(projectDTO.getOrgId()) || OrgConstant.NIIWOO_ORG_ID.equals(projectDTO.getOrgId()))
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(projectDTOList)) {
                hasOverdueRepayment = Boolean.TRUE;
            }
        }

        return hasOverdueRepayment;
    }

    private UserRoleEnum calcDefaultWithdrawAccountRole(String userId, List<AccountBaseResponse> accountBaseResponseList){
        UserRoleEnum defaultWithdrawAccountRole = null;

        AccountBaseResponse borrowAccount = null;
        AccountBaseResponse investAccount = null;
        for (AccountBaseResponse e : accountBaseResponseList) {
            if (UserRoleEnum.BORROWERS.getValue().equals(e.getAccountRole())) {
                borrowAccount = e;
            } else if (UserRoleEnum.INVESTOR.getValue().equals(e.getAccountRole())) {
                investAccount = e;
            }
        }

        if (Objects.nonNull(borrowAccount) && Objects.nonNull(investAccount)) {
            //比较借款账户与投资账户的余额大小
            BigDecimal borrowAccountBalance = borrowAccount.getAvailableAmount();
            BigDecimal investAccountBalance = investAccount.getAvailableAmount();

            //判断用户当天是否需要还款
            Boolean hasTodayRepayment = this.hasTodayRepayment(userId);
            if (hasTodayRepayment) {
                if (investAccountBalance.compareTo(BigDecimal.ZERO) == 0 && borrowAccountBalance.compareTo(BigDecimal.ZERO) > 0) {
                    //借款账户
                    defaultWithdrawAccountRole = UserRoleEnum.BORROWERS;
                } else {
                    //投资账户
                    defaultWithdrawAccountRole = UserRoleEnum.INVESTOR;
                }
            } else {
                //非还款日且非逾期:逾期的已在withdrawCheck中被拦截了
                if (borrowAccountBalance.compareTo(BigDecimal.ZERO) == 0 && investAccountBalance.compareTo(BigDecimal.ZERO) > 0) {
                    //投资账户
                    defaultWithdrawAccountRole = UserRoleEnum.INVESTOR;
                } else {
                    //借款账户
                    defaultWithdrawAccountRole = UserRoleEnum.BORROWERS;
                }
            }
        }

        return defaultWithdrawAccountRole;
    }


//    //TODO 上线屏蔽
    @AuthIgnore
    @PostMapping("/intercepMTxJjd24TuSV1t0oeMT1BcVLVZYkB2n0")
    @ApiOperation("提现拦截方法，仅用于测试")
    public Result<InterceptWithdrawResponse> withdrawIntercept(String withdrawRequestNo){

        InterceptWithdrawRequest request = new InterceptWithdrawRequest();
        request.setWithdrawRequestNo(withdrawRequestNo);
        request.setRequestNo(lanMaoSequence.getRequestNo());

        InterceptWithdrawResponse response = null;
        log.info("提现拦截请求：{}", JSON.toJSONString(request));

        try{
            CompletableFuture<InterceptWithdrawResponse> future = lanMaoDirectService.interceptWithdraw(request);
            response = future.get();
            log.info("提现拦截响应：{}", JSON.toJSONString(response));
        }catch(Exception e){
            log.error("提现拦截请求异常：{}",JSON.toJSONString(request),e);
        }
        return Result.with(response);
    }
//
//
    @AuthIgnore
    @PostMapping("/userInfoMLyPdFkU2tWq0gPndvuxMum9VxGLIiyT")
    @ApiOperation("查询存管实时用户信息")
    public Result<QueryUserInformationResponse> queryUserInformation(String platformUserNo){

        QueryUserInformationRequest request = new QueryUserInformationRequest();
        request.setRequestNo(lanMaoSequence.getRequestNo());
        request.setPlatformUserNo(platformUserNo);

        QueryUserInformationResponse response = null;
        log.info("查询用户存管信息：{}", JSON.toJSONString(request));

        try{
            CompletableFuture<QueryUserInformationResponse> future = lanMaoDirectService.queryUserInformation(request);
            response = future.get();
            log.info("查询用户存管信息：{}", JSON.toJSONString(response));
        }catch(Exception e){
            log.error("查询用户存管信息：{}",JSON.toJSONString(request),e);
        }
        return Result.with(response);
    }

    @AuthIgnore
    @PostMapping("/withdrawCancelB2zQwekvthzu7xmSK0i3XcqGotARgv2y")
    @ApiOperation("查询存管实时用户信息")
    public Result<ConfirmWithdrawResponse> withdrawCancel(String requestNo){
        //向存管发送取消提现的命令
        ConfirmWithdrawRequest confirmWithdrawRequest = new ConfirmWithdrawRequest();
        confirmWithdrawRequest.setRequestNo(lanMaoSequence.getRequestNo());
        confirmWithdrawRequest.setPreTransactionNo(requestNo);
        CompletableFuture<ConfirmWithdrawResponse> future = lanMaoDirectService.cancelWithdraw(confirmWithdrawRequest);
        ConfirmWithdrawResponse confirmWithdrawResponse = null;
        try {
            log.info("懒猫提取消请求{}：{}",requestNo,JSON.toJSONString(confirmWithdrawRequest));
            confirmWithdrawResponse = future.get();
            log.info("懒猫提现取消响应{}：{}",requestNo,JSON.toJSONString(confirmWithdrawResponse));
        } catch (Exception e) {
            log.error("懒猫提现取消接口调用异常:{}", JSON.toJSONString(confirmWithdrawRequest), e);
        }
        return Result.with(confirmWithdrawResponse);
    }



    /**
     *
     * @param requestNo
     * @return
     */
    /*@AuthIgnore
    @PostMapping("/handWithdrawPaymentFail_ufefw8e3j248sd34jhas922kfd4FFG")
    @ApiOperation("手工触发提现失败流程")
    public Result<SubmitWithdrawResponseVO> handWithdrawPaymentFail(String requestNo) {
        Assert.notNull(requestNo,"requestNo不能为空");
        WithdrawNotifyRequestDTO withdrawNotifyRequestDTO = new WithdrawNotifyRequestDTO();
        withdrawNotifyRequestDTO.setRequestNo(requestNo);
        withdrawNotifyRequestDTO.setOperateUserId(0L);
        withdrawNotifyRequestDTO.setEndTypeEnum(WithdrawEndTypeEnum.HANGDWORK);
        withdrawDubboService.withdrawPaymentFail(withdrawNotifyRequestDTO);

        return Result.with(null);

    }*/

}
